package com.example.firstopengl.util;

import android.util.Log;

import static android.content.ContentValues.TAG;
import static android.opengl.GLES20.GL_COMPILE_STATUS;
import static android.opengl.GLES20.GL_FRAGMENT_SHADER;
import static android.opengl.GLES20.GL_INVALID_VALUE;
import static android.opengl.GLES20.GL_LINK_STATUS;
import static android.opengl.GLES20.GL_VALIDATE_STATUS;
import static android.opengl.GLES20.GL_VERTEX_SHADER;
import static android.opengl.GLES20.glAttachShader;
import static android.opengl.GLES20.glCompileShader;
import static android.opengl.GLES20.glCreateProgram;
import static android.opengl.GLES20.glCreateShader;
import static android.opengl.GLES20.glDeleteProgram;
import static android.opengl.GLES20.glDeleteShader;
import static android.opengl.GLES20.glGetError;
import static android.opengl.GLES20.glGetProgramInfoLog;
import static android.opengl.GLES20.glGetProgramiv;
import static android.opengl.GLES20.glGetShaderiv;
import static android.opengl.GLES20.glLinkProgram;
import static android.opengl.GLES20.glShaderSource;
import static android.opengl.GLES20.glValidateProgram;

/**
 * Created by liqian-ps on 2017/6/27.
 */

public class ShaderHelper {
    private final static String TAG = ShaderHelper.class.getName();

    public static int compileVertexShader(String shaderCode) {
        return compileShader(GL_VERTEX_SHADER, shaderCode);
    }

    public static int compileFragmentShader(String shaderCode) {
        return compileShader(GL_FRAGMENT_SHADER, shaderCode);
    }

    public static int compileShader(int type, String shaderCode) {
        final int shaderObjectId = glCreateShader(type);

        if (shaderObjectId == 0) {
            if (LoggerConfig.ON) {
                Log.e(TAG, "glCreateShader error :"+ glGetError());

            }
            return 0;
        }

        glShaderSource(shaderObjectId, shaderCode);
        Log.e(TAG, "glShaderSource :"+glGetError());
        glCompileShader(shaderObjectId);
        Log.e(TAG, "glCompileShader :"+glGetError());

        final int[] compileState = new int[1];
        glGetShaderiv(shaderObjectId, GL_COMPILE_STATUS, compileState, 0);

        if (compileState[0] == 0) {
            glDeleteShader(shaderObjectId);

            if (LoggerConfig.ON) {
                Log.e(TAG, "compile shader error :"+glGetError());
            }

            return 0;
        }

        return shaderObjectId;
    }

    public static int linkProgram(int vertexShader, int fragmentShader) {
        final int programObjectId = glCreateProgram();
        if (programObjectId == 0) {
            if (LoggerConfig.ON) {
                Log.e(TAG, "glCreateProgram ERROR");
            }
            return 0;
        }

        glAttachShader(programObjectId, vertexShader);
        glAttachShader(programObjectId, fragmentShader);

        glLinkProgram(programObjectId);

        final int[] linkState = new int[1];
        glGetProgramiv(programObjectId, GL_LINK_STATUS, linkState, 0);

        if (LoggerConfig.ON) {
            Log.e(TAG, "linkProgram info" + glGetProgramInfoLog(programObjectId));
        }
        if (linkState[0] == 0) {
            glDeleteProgram(programObjectId);
            Log.e(TAG, "link program error");
            return 0;
        }

        return programObjectId;

    }

    public static int buildProgram(String vertexShader, String fragmentShader){
        int vertexObject = compileVertexShader(vertexShader);
        int fragmentObject = compileFragmentShader(fragmentShader);
        int program = linkProgram(vertexObject, fragmentObject);
        if(LoggerConfig.ON){
            Log.e(TAG, ""+validateProgram(program));
        }
        return program;
    }

    public static boolean validateProgram(int programObjectId) {

        glValidateProgram(programObjectId);
        final int[] valideState = new int[1];
        glGetProgramiv(programObjectId, GL_VALIDATE_STATUS, valideState, 0);

        if(LoggerConfig.ON){
            Log.e(TAG, "getPrograminfo \n"+glGetProgramInfoLog(programObjectId));
        }
        return valideState[0] != 0;
    }
}
